#include "diffsecondstest.h"
#include <stdexcept>

void DiffSecondsTest::initTestCase()
{
    qDebug() << "=== 初始化 DiffSeconds 测试用例 ===";

    // 初始化路径
    testDataFileBase = getTestDataBasePath();
    testResultFileBase = getTestResultBasePath();

    qDebug() << "测试数据基础路径:" << testDataFileBase;
    qDebug() << "测试结果基础路径:" << testResultFileBase;

    // 验证路径
    QDir testDataDir(testDataFileBase);
    if (!testDataDir.exists()) {
        qFatal("❌ 测试数据目录不存在: %s", testDataFileBase.toUtf8().constData());
    }

    QDir testResultDir(testResultFileBase);
    if (!testResultDir.exists()) {
        qDebug() << "创建测试结果目录...";
        if (testResultDir.mkpath(".")) {
            qDebug() << "✅ 测试结果目录创建成功";
        } else {
            qWarning() << "❌ 测试结果目录创建失败";
        }
    }

    qDebug() << "✅ DiffSeconds 测试环境初始化完成";
}

QString DiffSecondsTest::getTestDataBasePath()
{
    QDir currentDir(QDir::currentPath());

    // 从构建目录回退5级到 algorithm-test 目录
    QDir targetDir = currentDir.filePath("../../../../../test_data");
    QString absolutePath = targetDir.absolutePath() + "/";

    if (targetDir.exists()) {
        qDebug() << "✅ 使用相对路径找到测试数据:" << absolutePath;
        return absolutePath;
    } else {
        qWarning() << "❌ 相对路径找不到测试数据，使用硬编码路径";
        return "D:/Work/algorithm-test/test_data/";
    }
}

QString DiffSecondsTest::getTestResultBasePath()
{
    QDir currentDir(QDir::currentPath());

    // 从构建目录回退5级到 algorithm-test 目录
    QDir targetDir = currentDir.filePath("../../../../../test_result");
    QString absolutePath = targetDir.absolutePath() + "/";

    if (targetDir.exists()) {
        qDebug() << "✅ 使用相对路径找到测试结果路径:" << absolutePath;
        return absolutePath;
    } else {
        // 尝试创建目录
        if (targetDir.mkpath(".")) {
            qDebug() << "✅ 创建测试结果路径:" << absolutePath;
            return absolutePath;
        } else {
            qWarning() << "❌ 无法创建测试结果路径，使用硬编码路径";
            return "D:/Work/algorithm-test/test_result/";
        }
    }
}

QJsonArray DiffSecondsTest::readJsonArray(const QString& filePath)
{
    qDebug() << "读取JSON数组文件:" << filePath;

    QFileInfo fileInfo(filePath);
    qDebug() << "文件绝对路径:" << fileInfo.absoluteFilePath();
    qDebug() << "文件是否存在:" << fileInfo.exists();

    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        QString errorMsg = QString("无法打开文件：%1").arg(filePath);
        qWarning() << errorMsg;
        throw std::runtime_error(errorMsg.toStdString());
    }

    QByteArray data = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull()) {
        qWarning() << "JSON解析失败，文件内容:" << QString(data).left(100) << "...";
        throw std::runtime_error("JSON解析失败");
    }

    qDebug() << "JSON数组解析成功，元素数量:" << doc.array().size();
    return doc.array();
}

QJsonObject DiffSecondsTest::readJsonObject(const QString& filePath)
{
    qDebug() << "读取JSON对象文件:" << filePath;

    QFileInfo fileInfo(filePath);
    qDebug() << "文件绝对路径:" << fileInfo.absoluteFilePath();
    qDebug() << "文件是否存在:" << fileInfo.exists();

    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        QString errorMsg = QString("无法打开文件：%1").arg(filePath);
        qWarning() << errorMsg;
        throw std::runtime_error(errorMsg.toStdString());
    }

    QByteArray data = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull()) {
        qWarning() << "JSON解析失败，文件内容:" << QString(data).left(100) << "...";
        throw std::runtime_error("JSON解析失败");
    }

    qDebug() << "JSON对象解析成功，键数量:" << doc.object().keys().size();
    return doc.object();
}

void DiffSecondsTest::createFileRecursion(const QString& fileName)
{
    qDebug() << "创建文件:" << fileName;

    QFileInfo fileInfo(fileName);
    QDir dir = fileInfo.absoluteDir();

    if (!dir.exists()) {
        qDebug() << "创建目录...";
        if (dir.mkpath(".")) {
            qDebug() << "目录创建成功";
        } else {
            qWarning() << "目录创建失败";
        }
    }

    QFile file(fileName);
    if (!file.exists()) {
        if (file.open(QIODevice::WriteOnly)) {
            qDebug() << "文件创建成功";
            file.close();
        } else {
            qWarning() << "文件创建失败";
        }
    } else {
        qDebug() << "文件已存在";
    }
}

QTime DiffSecondsTest::parseTime(const QString& timeStr)
{
    if (timeStr.isEmpty()) {
        return QTime();
    }

    // 处理类似 "09:00:00" 的时间字符串
    QTime time = QTime::fromString(timeStr, "hh:mm:ss");
    if (!time.isValid()) {
        qWarning() << "时间格式无效:" << timeStr;
        throw std::runtime_error("Invalid time format: " + timeStr.toStdString());
    }

    return time;
}

bool DiffSecondsTest::loadGlobalTestData(const QString& folderPath)
{
    qDebug() << "=== 开始加载全局测试数据 ===";
    qDebug() << "数据文件夹路径:" << folderPath;

    try {
        QDir dataDir(folderPath);
        if (!dataDir.exists()) {
            qWarning() << "数据文件夹不存在:" << folderPath;
            return false;
        }

        // 加载特殊日期工作时间数据
        QString specialDatePath = folderPath + "special_date_work_time.json";
        qDebug() << "加载特殊日期工作时间文件:" << specialDatePath;
        QJsonArray specialDateWorkTimes = readJsonArray(specialDatePath);
        dateWorkTimeList.clear();

        qDebug() << "特殊日期工作时间详情：";
        for (const QJsonValue& value : specialDateWorkTimes) {
            QJsonObject obj = value.toObject();

            QString appointedDateStr = obj["appointedDate"].toString();
            QString dateOnly = appointedDateStr.left(10);
            QDate appointedDate = QDate::fromString(dateOnly, "yyyy-MM-dd");

            if (!appointedDate.isValid()) {
                qWarning() << "  日期解析失败！原始字符串:" << appointedDateStr;
                continue;
            }
            qDebug() << "  日期:" << appointedDate.toString("yyyy-MM-dd");

            QVector<CWorkTime> workTimeVec;
            QString startTimeStr = obj["workTimeStart"].toString();
            QString endTimeStr = obj["workTimeEnd"].toString();

            QString timeStartOnly = startTimeStr.right(8);
            QString timeEndOnly = endTimeStr.right(8);

            QTime startTime = QTime::fromString(timeStartOnly, "hh:mm:ss");
            QTime endTime = QTime::fromString(timeEndOnly, "hh:mm:ss");

            if (!startTime.isValid() || !endTime.isValid()) {
                qWarning() << "  时间解析失败！原始字符串:" << startTimeStr << "-" << endTimeStr;
                continue;
            }
            qDebug() << "    时间段:" << startTime.toString("hh:mm:ss") << "-" << endTime.toString("hh:mm:ss");

            CWorkTime workTime;
            workTime.update(startTime, endTime);
            workTimeVec.append(workTime);

            dateWorkTimeList.append(qMakePair(appointedDate, workTimeVec));
        }

        // 加载常规每周工作时间数据
        QString normalWorkTimePath = folderPath + "normal_work_time.json";
        qDebug() << "加载常规工作时间文件:" << normalWorkTimePath;
        QJsonObject normalWorkTimeData = readJsonObject(normalWorkTimePath);
        mHashNormalDayToWorkTime.clear();

        qDebug() << "常规每周工作时间详情：";
        for (auto it = normalWorkTimeData.begin(); it != normalWorkTimeData.end(); ++it) {
            int dayOfWeek = it.key().toInt();
            qDebug() << "  星期" << dayOfWeek << ":";

            QJsonArray workTimeArray = it.value().toArray();
            QVector<CWorkTime> workTimeList;

            for (const QJsonValue& value : workTimeArray) {
                QJsonObject workTimeObj = value.toObject();
                QTime startTime = QTime::fromString(workTimeObj["startTime"].toString(), "hh:mm:ss");
                QTime endTime = QTime::fromString(workTimeObj["endTime"].toString(), "hh:mm:ss");
                qDebug() << "    时间段:" << startTime.toString("hh:mm:ss") << "-" << endTime.toString("hh:mm:ss");

                CWorkTime workTime;
                workTime.update(startTime, endTime);
                workTimeList.append(workTime);
            }

            mHashNormalDayToWorkTime[dayOfWeek] = workTimeList;
        }

        // 加载节假日数据
        QString holidayPath = folderPath + "holidays.json";
        qDebug() << "加载节假日文件:" << holidayPath;
        QJsonArray holidayArray = readJsonArray(holidayPath);
        mSetHoliday.clear();

        qDebug() << "节假日详情：";
        for (const QJsonValue& value : holidayArray) {
            QDate holiday = QDate::fromString(value.toString(), "yyyy-MM-dd");
            mSetHoliday.insert(holiday);
            qDebug() << "  -" << holiday.toString("yyyy-MM-dd");
        }

        qDebug() << "=== 全局数据加载完成 ===";
        qDebug() << "特殊日期工作时间数据总数：" << dateWorkTimeList.size();
        qDebug() << "常规每周工作时间数据总数：" << mHashNormalDayToWorkTime.size();
        qDebug() << "节假日数据总数：" << mSetHoliday.size();

        return true;
    }
    catch (const std::exception& e) {
        qWarning() << "加载测试数据失败：" << e.what();
        return false;
    }
}

void DiffSecondsTest::writeResultToFile(const QString& fileName, const QVector<int>& results)
{
    createFileRecursion(fileName);
    QFile resultFile(fileName);
    if (resultFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QTextStream resultStream(&resultFile);
        for (int result : results) {
            resultStream << result << "\n";
        }
        resultFile.close();
        qDebug() << "结果写入文件:" << fileName << "结果数量:" << results.size();
    } else {
        qWarning() << "无法创建结果文件：" << fileName;
    }
}

void DiffSecondsTest::testDiffSeconds()
{
    qDebug() << "=== 开始测试 DiffSeconds 方法 ===";
    qDebug() << "测试数据基础路径:" << testDataFileBase;
    qDebug() << "测试结果基础路径:" << testResultFileBase;

    // 遍历 random_case_1 到 random_case_50 文件夹以及 manual_case_1 到 manual_case_2 文件夹
    for (int i = 1; i <= 52; i++) {
        try {
            QString folderPath;
            QString resultFileName;

            if (i <= 50) {
                folderPath = testDataFileBase + QString("diffSeconds/random_case_%1/").arg(i);
                resultFileName = testResultFileBase + QString("diffSeconds_c/random_case_%1.txt").arg(i);
            } else {
                folderPath = testDataFileBase + QString("diffSeconds/manual_case_%1/").arg(i - 50);
                resultFileName = testResultFileBase + QString("diffSeconds_c/manual_case_%1.txt").arg(i - 50);
            }

            QDir folder(folderPath);
            if (!folder.exists()) {
                qWarning() << "文件夹不存在：" << folderPath;
                continue;
            }

            qDebug() << "\n=== 处理测试用例" << (i <= 50 ? "random_case_" : "manual_case_") << (i <= 50 ? i : (i - 50)) << "===";

            // 为每个文件夹重新加载全局测试数据
            if (!loadGlobalTestData(folderPath)) {
                qWarning() << "加载全局测试数据失败：" << folderPath;
                continue;
            }

            // 加载测试用例数据
            QString testCasesPath = folderPath + "test_cases.json";
            qDebug() << "加载测试用例文件:" << testCasesPath;
            QJsonObject testData = readJsonObject(testCasesPath);
            QJsonArray testCases = testData["testCases"].toArray();
            qDebug() << "测试用例数量:" << testCases.size();

            QVector<int> results;

            for (int j = 0; j < testCases.size(); j++) {
                QJsonObject testCase = testCases[j].toObject();

                // 解析开始和结束日期时间
                QString startDateStr = testCase["startDate"].toString();
                QString endDateStr = testCase["endDate"].toString();

                qDebug() << "\n--- 执行测试用例" << (j + 1) << "---";
                qDebug() << "开始日期时间字符串:" << startDateStr;
                qDebug() << "结束日期时间字符串:" << endDateStr;

                // 解析日期时间 (格式: "yyyy-MM-dd HH:mm:ss")
                QDateTime startDateTime = QDateTime::fromString(startDateStr, "yyyy-MM-dd HH:mm:ss");
                QDateTime endDateTime = QDateTime::fromString(endDateStr, "yyyy-MM-dd HH:mm:ss");

                if (!startDateTime.isValid() || !endDateTime.isValid()) {
                    qWarning() << "❌ 日期时间解析失败!";
                    results.append(0);
                    continue;
                }

                qDebug() << "开始日期时间:" << startDateTime.toString("yyyy-MM-dd HH:mm:ss");
                qDebug() << "结束日期时间:" << endDateTime.toString("yyyy-MM-dd HH:mm:ss");

                // 检查时间范围
                if (startDateTime >= endDateTime) {
                    qDebug() << "❌ 开始时间大于等于结束时间，返回0";
                    results.append(0);
                    continue;
                }

                // 创建服务实例并设置数据
                CHolidaySet service;
                service.mHashNormalDayToWorkTime = mHashNormalDayToWorkTime;
                service.mSetHoliday = mSetHoliday;

                // 调用 DiffSeconds 方法
                qDebug() << "=== 调用 DiffSeconds 方法 ===";
                int result = service.DiffSeconds(startDateTime, endDateTime);

                qDebug() << "计算结果:" << result << "秒 (" << (result / 3600.0) << "小时)";
                results.append(result);
            }

            // 写入测试结果
            writeResultToFile(resultFileName, results);

            qDebug() << "测试完成:" << (i <= 50 ? "random_case_" : "manual_case_") << (i <= 50 ? i : (i - 50));

        } catch (const std::exception& e) {
            qWarning() << "测试失败:" << (i <= 50 ? "random_case_" : "manual_case_") << (i <= 50 ? i : (i - 50)) << "错误:" << e.what();
        }
    }
}

void DiffSecondsTest::cleanupTestCase()
{
    qDebug() << "清理 DiffSeconds 测试用例...";
}
